import {
  CMEVENTS,
  contextMenuManager,
  EventsRes,
  IArcOfCircleParams,
  ICircleParams,
  ICurve,
  IEllipseParams,
} from '@amcax/base';
import {
  SKETCH_CENTEREVENTS,
  sketchEventCenter,
} from '@app-cad/environments/nextcad/events/SketchEventCenter';
import { Vector2tuple, Vector3 } from 'three-legacy';
import CmdBase from '../../CmdBase';
import {
  CURVE,
  MENU_ITEMS,
  MouseState,
  P_Line,
  P_Line2,
  SET_RIGHT_MENU,
  State,
} from './types';
import { DimRadiusTool } from '../dimension/DimRadiusTool';
import { AnnotationType, EllipseState } from '../dimension/types';
import { dimRender } from '../cmd-render-pick/render';
import { DimLinear } from '../dimension/DimLinear';
import { DimDiameterTool } from '../dimension/DimDiameter';
import {
  addDimension,
  axis,
  hiddenPoint,
  isParallel,
} from '@app-cad/common/utils';
import { DimAngleTool } from '../dimension/DimAngleTool';
import { DimRightMenu } from '@app-cad/environments/nextcad/widgets/ContextMenu/DimRightMenu';
import { ctx2, userEvents } from '@app-cad/module';
import { DimEllipseTool } from '../dimension/DimEllipseRadius';
import { isDriven } from '../cmd-render-pick/tools';
import DimBase from '../dimension/DimBase';
import { DimInfo } from '../cmd-render-pick/type';
export default class CmdInteractor extends CmdBase {
  drawState: MouseState = State.NONE; // 当前状态
  curveIds: string[] = []; // 选中曲线id
  dimLinear: DimBase; // 标注
  isExist: boolean = false; // 是否已存在标注
  vertices: Vector2tuple[][];
  curveTypes: string[] = new Array(2); // 选中的曲线类型
  firstCurve: ICurve = null; // 第一个曲线信息
  dimParam = null; // 保存标注参数
  singleLineIds: string[] = null; // 单条直线两个端点id
  singleLineVex: Vector2tuple[][] = null; // 单条直线两个端点id
  pointRelatives = [];
  count = 0;
  rightMenuOpen = false;
  constructor() {
    super();
    this.registerEvents();
    this.picker.clickNull();
  }

  reset() {
    this.drawState = State.NONE;
    this.isExist = false;
    this.curveTypes = new Array(2);
    this.firstCurve = null;
    this.pickSnapInfo = null;
    this.dimParam = null;
    this.singleLineIds = null;
    this.singleLineVex = null;
    this.count = 0;
    this.rightMenuOpen = false;
  }

  unregisterEvents() {
    sketchEventCenter()
      .off(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .off(SKETCH_CENTEREVENTS.POINTERUP, this.onMouseUp)
      .off(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .off(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .setDefault();
    userEvents.off(CMEVENTS.MODEL_RIGHT_CLICK, this.upMenuItes);
  }

  registerEvents() {
    sketchEventCenter()
      .setState('dimIntegration')
      .on(SKETCH_CENTEREVENTS.POINTERDOWN, this.onMouseDown)
      .on(SKETCH_CENTEREVENTS.POINTERUP, this.onMouseUp)
      .on(SKETCH_CENTEREVENTS.POINTERMOVE, this.onMouseMove)
      .on(SKETCH_CENTEREVENTS.KEYUP, this.onKeyUp)
      .addExit(this.destroy.bind(this));
    userEvents.on(CMEVENTS.MODEL_RIGHT_CLICK, this.upMenuItes);
    this.unPickedIds = Array.from(hiddenPoint);
  }

  onMouseDown = ({ button }: EventsRes) => {
    if (button.onLeft && this.pickSnapInfo) {
      this.dimLinear?.unClickFocus();
    }
  };
  onMouseUp = ({ button }: EventsRes) => {
    if (button.onLeft) {
      if (
        this.pickSnapInfo?.type &&
        this.pickSnapInfo?.type !== 'Bspline' &&
        this.drawState < State.DRAWTWO
      ) {
        if (this.pickSnapInfo) {
          this.selectCurve();
        }
      } else if (this.drawState !== State.NONE && this.dimLinear?.isDisabled) {
        // 若没有拾取到且当前注释不可编辑，因为无法触发focus进入callback函数，则应当直接添加约束
        this.finishDraw();
        return;
      }
    } else if (button.onRight && !this.closeRightClick) {
      this.drawState = State.NONE;
      this.reset();
      this.releaseObjects();
    } else if (button.onRight && this.closeRightClick) {
      userEvents.emit(SET_RIGHT_MENU, this.setMenuItes());
    }
  };
  upMenuItes = (event: PointerEvent) => {
    setTimeout(() => {
      contextMenuManager.show(event, DimRightMenu.id);
    });
  };
  action = (params) => {
    if (this.dimLinear) {
      if (params.type === AnnotationType.RadiusAnno) {
        if (params.curve === 'radius') {
          this.addRadius();
        } else {
          this.addDiameter();
        }
      } else {
        // 椭圆长轴短轴
        if (
          params?.curve === EllipseState.major ||
          params?.curve === EllipseState.minor
        ) {
          this.addEllipseDim(null, params.type);
        } else {
          this.addLine(params.type);
        }
      }
      this.rightMenuOpen = false;
      ctx2.viewer.requestRender();
    }
  };
  setMenuItes = () => {
    const ids = [];
    if (this.curveIds.length === 1) {
      ids.push(this.curveIds[0]);
    } else if (this.pointRelatives.length === 2) {
      this.pointRelatives[0].forEach((id) => {
        if (this.pointRelatives[1].includes(id)) {
          ids.push(id);
        }
      });
    }
    if (ids.length === 1 && isDriven().curveIsFixed(ids)) {
      return [];
    }
    if (
      P_Line.includes(this.curveTypes.join('-')) ||
      this.curveTypes.join('-') === 'Line-Line' ||
      this.pickSnapInfo?.type ||
      this.drawState === State.FINISH ||
      this.drawState === State.NONE
    ) {
      return [];
    }
    this.rightMenuOpen = true;
    return MENU_ITEMS(this.action)[this.dimLinear.userData.type] || [];
  };
  hasCenter(type?: string) {
    return CURVE.includes(type || this.pickSnapInfo?.type);
  }
  onMouseMove = (e: EventsRes) => {
    this.setMouseWV(e, false, false);
    if (this.drawState === State.DRAWONE || this.drawState === State.DRAWTWO) {
      this.dimLinear?.update({
        labelPos: this.mouseWV,
      });
      ctx2.viewer.requestRender();
    }
  };
  callback = (status: 'focus' | 'blur') => {
    if (status === 'focus' && this.drawState <= State.DRAWTWO) {
      this.drawState = State.INPUT;
    } else if (this.drawState === State.INPUT && status === 'blur') {
      this.finishDraw();
    }
    // if (this.isExist) { // 添加过约束
    //   if (this.count === 1 && !this.rightMenuOpen) {
    //     this.finishDraw();
    //   } else {
    //     this.count = 1;
    //   }
    // }
  };
  selectCurve = () => {
    const id = this.pickSnapInfo?.id;
    this.singleLineIds = null;
    this.singleLineVex = null;
    if (this.curveIds.includes(id) || this.firstCurve?.relative[0] === id) {
      return;
    }
    this.curveTypes[this.drawState] = this.pickSnapInfo?.type;
    this.curveIds.push(id);
    let vertice = this.pickSnapInfo.vertices;
    if (this.hasCenter()) {
      const param = this.pickSnapInfo?.params as { center: Vector2tuple };
      vertice = [param.center];
    }
    if (this.pickSnapInfo.type === 'Point') {
      this.pointRelatives.push(this.pickSnapInfo.relative);
    }
    if (this.drawState === State.NONE) {
      const curType = this.curveTypes[this.drawState];
      this.firstCurve = this.pickSnapInfo;
      this.vertices = [vertice];
      if (curType === 'ArcOfCircle') {
        const params = this.pickSnapInfo.params as IArcOfCircleParams;
        const point1 = new Vector3(params.point1[0], params.point1[1], 0);
        const point2 = new Vector3(params.point2[0], params.point2[1], 0);
        const center = new Vector3(params.center[0], params.center[1], 0);
        const radius = params.radius;
        this.addRadius({ point1, point2, center, radius, curveType: curType });
      } else if (curType === 'Circle') {
        const params = this.pickSnapInfo.params as ICircleParams;
        this.addDiameter({
          center: new Vector3(params.center[0], params.center[1], 0),
          radius: params.radius,
        });
      } else if (curType === 'Line' && !axis.includes(this.curveIds[0])) {
        this.singleLineIds = [
          this.pickSnapInfo.relative[0],
          this.pickSnapInfo.relative[1],
        ];
        this.singleLineVex = [[vertice[0]], [vertice[1]]];
        this.addLine(AnnotationType.DistanceAnno);
      } else if (curType === 'Ellipse') {
        const params = this.pickSnapInfo.params as IEllipseParams;
        this.addEllipseDim(params, AnnotationType.MajorRadiusAnno);
      }
    } else if (this.drawState === State.DRAWONE) {
      // 第一个点击的是曲线
      if (this.hasCenter(this.firstCurve.type)) {
        this.curveIds[0] = this.firstCurve.relative[0];
      }
      // 第二个点击的是曲线
      if (this.hasCenter()) {
        this.curveIds[1] = this.pickSnapInfo.relative[0];
      }
      if (
        P_Line2.includes(this.curveTypes.join('-')) &&
        (this.pickSnapInfo.relative.includes(this.curveIds[0]) ||
          this.firstCurve?.relative.includes(this.curveIds[1]))
      ) {
        return;
      }
      this.vertices.push(vertice);
      if (this.curveTypes.join('-') === 'Line-Line') {
        const parallel = isParallel(
          this.v2ToVec(this.vertices[0]),
          this.v2ToVec(this.vertices[1]),
        );
        if (!parallel) {
          this.addAngle();
        } else {
          this.addLine(AnnotationType.DistanceAnno);
        }
      } else {
        this.addLine(AnnotationType.DistanceAnno);
      }
    }
    this.drawState = this.drawState + 1;
  };
  addEllipseDim = (parmas?, dCon?: AnnotationType) => {
    this.dimParam = parmas || this.dimParam;
    this.annotation(() => {
      this.dimLinear = new DimEllipseTool({
        dimConstraint: dCon || AnnotationType.MajorRadiusAnno,
        curveIds: this.curveIds,
        ...this.dimParam,
        labelPos: this.mouseWV,
        callback: this.callback,
      });
    });
  };
  v2ToVec = (v2: Vector2tuple[]) => {
    return new Vector3(v2[1][0] - v2[0][0], v2[1][1] - v2[0][1], 0).normalize();
  };
  addRadius = (parmas?) => {
    this.dimParam = parmas || this.dimParam;
    this.annotation(() => {
      this.dimLinear = new DimRadiusTool({
        dimConstraint: AnnotationType.RadiusAnno,
        curveIds: this.curveIds,
        ...this.dimParam,
        labelPos: this.mouseWV,
        callback: this.callback,
      });
    });
  };
  addDiameter = (parmas?) => {
    this.dimParam = parmas || this.dimParam;
    this.annotation(() => {
      this.dimLinear = new DimDiameterTool({
        dimConstraint: AnnotationType.RadiusAnno,
        curveIds: this.curveIds,
        ...this.dimParam,
        labelPos: this.mouseWV,
        callback: this.callback,
      });
    });
  };
  addLine = (dCon?: AnnotationType) => {
    this.arrangeIds();
    this.annotation(() => {
      this.dimLinear = new DimLinear({
        curveIds: this.singleLineIds || this.curveIds,
        dimConstraint: dCon || AnnotationType.DimensionAnno,
        lineVertices: this.singleLineVex || this.vertices,
        labelPos: this.mouseWV,
        callback: this.callback,
      });
    });
  };
  addAngle = () => {
    this.arrangeIds();
    this.annotation(() => {
      this.dimLinear = new DimAngleTool({
        lineVertices: this.vertices,
        curveIds: this.curveIds,
        dimConstraint: AnnotationType.AngleAnno,
        labelPos: this.mouseWV,
        callback: this.callback,
      });
    });
  };
  annotation = (dimfn) => {
    this.dimLinear?.destroy();
    this.dimLinear = null;
    if (!this.dimLinear) {
      dimfn();
      this.isExist = dimRender().isExistDim({
        objects: this.dimLinear.userData.objects,
        type: this.dimLinear.userData.type,
        curveIds: this.curveIds,
      });
      this.dimLinear.addTo(this.assisGroup);
    }
    if (this.isExist) {
      this.dimLinear.setDisable();
    } else {
      this.dimLinear.unDisable();
    }
    this.dimLinear?.labelFoucs();
  };
  // 遇到轴线  必须把轴线id作为第一个
  arrangeIds() {
    const curveIds = this.curveIds;
    if (
      (curveIds.length === 2 && ['ORIGIN', ...axis].includes(curveIds[1])) ||
      this.isOnAxis()
    ) {
      this.curveIds = [curveIds[1], curveIds[0]];
      this.vertices = [this.vertices[1], this.vertices[0]];
    }
  }
  // 点是否在轴线上
  isOnAxis = () => {
    let flag = false;
    if (this.vertices.length === 2) {
      const [p1, p2] = this.vertices[0];
      const [p3, p4] = this.vertices[1];
      flag =
        p3?.includes(0) &&
        p4?.includes(0) &&
        !p1?.includes(0) &&
        !p2?.includes(0);
    }
    return flag;
  };
  finishDraw = async () => {
    this.drawState = State.FINISH;
    const userData = this.dimLinear.userData;
    if (this.dimLinear.userData.type === AnnotationType.AngleAnno) {
      const angleDim = this.dimLinear as DimAngleTool;
      userData.value = angleDim.getDimDeg();
      userData.points = [...angleDim.getPosLv(), ...angleDim.getDimArcInfo()];
    } else {
      userData.points = this.dimLinear.getPosLv();
      userData.value = this.dimLinear.getVal();
    }
    addDimension(this.sketchId, userData as DimInfo, this.isExist).finally(
      () => {
        this.releaseObjects();
        this.reset();
      },
    );
  };

  releaseObjects() {
    this.assisGroup.clear();
    this.curveIds = [];
    this.dimLinear?.destroy();
    this.dimLinear = null;
    this.unPickedIds = [];
    ctx2.viewer.requestRender();
  }
}
